home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / storage / file / fd.c
Encoding:
C/C++ Source or Header  |  1993-04-11  |  29.8 KB  |  1,454 lines

  1. /*
  2.  * fd.c --
  3.  *    Virtual file descriptor code.
  4.  *
  5.  * Note:
  6.  *    Useful to get around the limit imposed be NOFILE (in stdio.h).
  7.  *        (well, sys/param.h at least)
  8.  *
  9.  * Also note: this whole thing is UNIX dependent.  (well 70% anyway)
  10.  *
  11.  * NOTE: SEQUENT OS BUG: on open w/ O_CREAT if EMFILE error occurs the
  12.  * file is *still* created in the directory.  Therefore, we must ensure
  13.  * fd descriptors are available before calling open if O_CREAT flag is
  14.  * set.
  15.  */
  16.  
  17. /*
  18.  * CURRENT HACK
  19.  *
  20.  * Problem: Postgres does a system(ld...) to do dynamic loading.  This
  21.  * will open several extra files in addition to those used by Postgres.
  22.  * We need to do this hack to guarentee that there are file descriptors free
  23.  * for ld to use.
  24.  *
  25.  * The current solution is to limit the number of files descriptors
  26.  * that this code will allocated at one time.  (it leaves RESERVE_FOR_LD
  27.  * free)
  28.  */
  29.  
  30. #include <sys/file.h>
  31. #include <sys/param.h>
  32. #include <errno.h>
  33. #include <sys/stat.h>
  34.  
  35. extern errno;
  36.  
  37. #include "tmp/c.h"
  38. #include "machine.h"    /* for BLCKSZ */
  39. #include "tmp/libpq-fs.h" /* for pgstat */
  40.  
  41. #ifdef PARALLELDEBUG
  42. #include "executor/paralleldebug.h"
  43. #endif
  44.  
  45. RcsId("$Header: /private/postgres/src/storage/file/RCS/fd.c,v 1.45 1992/08/11 21:33:58 mao Exp $");
  46.  
  47. #ifdef sequent
  48. #define RESERVE_FOR_LD    5
  49. #else
  50. #define RESERVE_FOR_LD    10
  51. #endif
  52.  
  53. #ifdef SONY_JUKEBOX
  54. #define RESERVE_FOR_JB    1
  55. #endif
  56.  
  57. #ifdef SONY_JUKEBOX
  58. #define    MAXFILES    ((NOFILE - RESERVE_FOR_LD) - RESERVE_FOR_JB)
  59. #else /* SONY_JUKEBOX */
  60. #define    MAXFILES    (NOFILE - RESERVE_FOR_LD)
  61. #endif /* SONY_JUKEBOX */
  62.  
  63. /* #define FDDEBUG /* */
  64.  
  65. /* Debugging.... */
  66.  
  67.  
  68. #ifdef FDDEBUG
  69. # define DO_DB(A) A
  70. # define private /* static */
  71. #else
  72. # define DO_DB(A) /* A */
  73. # define private static
  74. #endif
  75.  
  76. #define VFD_CLOSED -1
  77.  
  78. #include "storage/fd.h"
  79. #include "utils/log.h"
  80.  
  81. #define FileIsNotOpen(file) (VfdCache[file].fd == VFD_CLOSED)
  82.  
  83. typedef struct vfd {
  84.     signed short    fd;
  85.     unsigned short    fdstate;
  86.  
  87. #define FD_DIRTY    (1 << 0)
  88.  
  89.     FileNumber    nextFree;
  90.     FileNumber    lruMoreRecently;
  91.     FileNumber    lruLessRecently;
  92.     long        seekPos;
  93.     char        *fileName;
  94.     int        fileFlags;
  95.     int        fileMode;
  96. } Vfd;
  97.  
  98. /*
  99.  *
  100.  * Striped file descriptor struct
  101.  *
  102.  *
  103.  */
  104. int NStriping = 1;        /* degree of striping, default as 1 */
  105. int StripingMode = 0;        /* default striping mode to RAID 0 */
  106. typedef struct sfd {
  107.         FileNumber vfd[NDISKS];
  108.         int curStripe;
  109.         long seekPos;
  110.     long endPos;
  111.         FileNumber nextFree;
  112. } Sfd;
  113.  
  114. private Sfd *SfdCache;
  115.  
  116. /*
  117.  *
  118.  * Lru stands for Least Recently Used.
  119.  * Vfd stands for Virtual File Descriptor
  120.  *
  121.  */
  122.  
  123. /*
  124.  * Virtual File Descriptor array pointer and size
  125.  */
  126.  
  127. private    Vfd    *VfdCache;
  128.  
  129. private    Size    SizeVfdCache = 0;
  130. private Size    SizeSfdCache = 100;
  131.  
  132. /*
  133.  * Minimun number of file descriptors known to be free
  134.  */
  135.  
  136. private FreeFd = 0;
  137.  
  138. private    nfile = 0;
  139.  
  140. /*
  141.  * delete a file from the Last Recently Used ring.
  142.  * the ring is a doubly linked list that begins and
  143.  * ends on element zero.
  144.  *
  145.  * example:
  146.  *
  147.  *     /--less----\                /---------\
  148.  *     v           \              v           \
  149.  *   #0 --more---> LeastRecentlyUsed --more-\ \
  150.  *    ^\                                    | |
  151.  *     \\less--> MostRecentlyUsedFile   <---/ |
  152.  *      \more---/                    \--less--/
  153.  *
  154.  */
  155. void
  156. _dump_lru()
  157. {
  158.     int mru = VfdCache[0].lruLessRecently;
  159.     Vfd *vfdP = &VfdCache[mru];
  160.  
  161.     printf("MOST %d ", mru);
  162.     while (mru != 0)
  163.     {
  164.     mru = vfdP->lruLessRecently;
  165.     vfdP = &VfdCache[mru];
  166.         printf("%d ", mru);
  167.     }
  168.     printf("LEAST\n");
  169. }
  170. void
  171. EnableFDCache(enable)
  172. int enable;
  173. {
  174.     static int numEnabled;
  175. #ifdef DOUBLECHECK
  176.     static int fault;
  177.  
  178.     Assert(!fault);
  179. #endif
  180.  
  181.     if (!enable && --numEnabled)
  182.     return;
  183.     if (enable && numEnabled++)
  184.     return;
  185.  
  186. #ifdef DOUBLECHECK
  187.     ++fault;
  188. #endif
  189.     if (enable) {
  190.     EnableELog(1);
  191.     /* XXX */
  192.     } else {
  193.     EnableELog(0);
  194.     /* XXX */
  195.     }
  196. #ifdef DOUBLECHECK
  197.     --fault;
  198. #endif
  199. }
  200.  
  201.  
  202.  /*
  203.   * Private Routines
  204.   *
  205.   * Delete       - delete a file from the Lru ring
  206.   * LruDelete       - remove a file from the Lru ring and close
  207.   * Insert       - put a file at the front of the Lru ring
  208.   * LruInsert       - put a file at the front of the Lru ring and open
  209.   * AssertLruRoom  - make sure that there is a free fd.
  210.   * AllocateVfd       - grab a free (or new) file record (from VfdArray)
  211.   * FreeVfd       - free a file record
  212.   *
  213.   */
  214.  
  215. void
  216. LruDelete ARGS((
  217.     FileNumber    file
  218. ));
  219.  
  220. int
  221. LruInsert ARGS((
  222.     FileNumber    file
  223. ));
  224.  
  225. void
  226. AssertLruRoom();
  227.  
  228. FileNumber
  229. AllocateVfd();
  230.  
  231. void
  232. Delete (file)
  233.     FileNumber    file;
  234. {
  235.     Vfd    *fileP;
  236.  
  237.     DO_DB(printf("DEBUG:    Delete %d (%s)\n",file,VfdCache[file].fileName));
  238.     DO_DB(_dump_lru());
  239.  
  240.     Assert(file != 0);
  241.  
  242.     fileP = &VfdCache[file];
  243.     VfdCache[fileP->lruLessRecently].lruMoreRecently =
  244.         VfdCache[file].lruMoreRecently;
  245.     VfdCache[fileP->lruMoreRecently].lruLessRecently =
  246.         VfdCache[file].lruLessRecently;
  247.  
  248.     DO_DB(_dump_lru());
  249. }
  250.  
  251.  
  252. void
  253. LruDelete(file)
  254.     FileNumber    file;
  255. {
  256.     Vfd     *fileP;
  257.     int    returnValue;
  258.  
  259.     DO_DB(printf("DEBUG:    LruDelete %d (%s)\n",file,VfdCache[file].fileName));
  260.  
  261.     Assert(file != 0);
  262.  
  263.     fileP = &VfdCache[file];
  264.  
  265.     /* delete the vfd record from the LRU ring */
  266.     Delete(file);
  267.  
  268.     /* save the seek position */
  269.     fileP->seekPos = lseek(fileP->fd, 0L, L_INCR);
  270.     Assert( fileP->seekPos != -1);
  271.  
  272.     /* if we have written to the file, sync it */
  273.     if (fileP->fdstate & FD_DIRTY) {
  274. #ifndef linux
  275.         returnValue = fsync(fileP->fd);
  276.         Assert(returnValue != -1);
  277. #endif
  278.         fileP->fdstate &= ~FD_DIRTY;
  279.     }
  280.  
  281.     /* close the file */
  282.     returnValue = close(fileP->fd);
  283.     Assert(returnValue != -1);
  284.  
  285.     --nfile;
  286.     fileP->fd = VFD_CLOSED;
  287.  
  288.     /* note that there is now one more free real file descriptor */
  289.     FreeFd++;
  290. }
  291.  
  292. void
  293. Insert(file)
  294.     FileNumber    file;
  295. {
  296.     Vfd    *vfdP;
  297.  
  298.     DO_DB(printf("DEBUG:    Insert %d (%s)\n",file,VfdCache[file].fileName));
  299.     DO_DB(_dump_lru());
  300.  
  301.     vfdP = &VfdCache[file];
  302.  
  303.     vfdP->lruMoreRecently = 0;
  304.     vfdP->lruLessRecently = VfdCache[0].lruLessRecently;
  305.     VfdCache[0].lruLessRecently = file;
  306.     VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;
  307.  
  308.     DO_DB(_dump_lru());
  309. }
  310.  
  311. int
  312. LruInsert (file)
  313.     FileNumber    file;
  314. {
  315.     Vfd    *vfdP;
  316.     int    returnValue;
  317.  
  318.     DO_DB(printf("DEBUG:    LruInsert %d (%s)\n",file,VfdCache[file].fileName));
  319.  
  320.     vfdP = &VfdCache[file];
  321.  
  322.     if (FileIsNotOpen(file)) {
  323.            int tmpfd;
  324.  
  325.         /*
  326.          * Open the requested file
  327.          *
  328.          * Note, due to bugs in sequent operating system and
  329.          * possibly other OS's, we must ensure a file descriptor
  330.          * is available before attempting to open a normal file
  331.          * if O_CREAT is specified.
  332.          */
  333.  
  334. tryAgain:
  335.         tmpfd = open("/dev/null", O_CREAT|O_RDWR, 0666);
  336.         if (tmpfd < 0) {
  337.             FreeFd = 0;
  338.             errno = 0;
  339.             AssertLruRoom();
  340.             goto tryAgain;
  341.         } else {
  342.             close(tmpfd);
  343.         }
  344.         vfdP->fd = open(vfdP->fileName,vfdP->fileFlags,vfdP->fileMode);
  345.  
  346.         if (vfdP->fd < 0) {
  347.             DO_DB(printf("RE_OPEN FAILED: %d\n", errno));
  348.             return (vfdP->fd);
  349.         } else {
  350.             DO_DB(printf("RE_OPEN SUCESS\n"));
  351.             ++nfile;
  352.         }
  353.  
  354.         /* seek to the right position */
  355.         if (vfdP->seekPos != 0L) {
  356.             returnValue = lseek(vfdP->fd, vfdP->seekPos, L_SET);
  357.             Assert(returnValue != -1);
  358.         }
  359.  
  360.         /* init state on open */
  361.         vfdP->fdstate = 0x0;
  362.  
  363.         /* note that a file descriptor has been used up */
  364.         if (FreeFd > 0)
  365.             FreeFd--;
  366.     }
  367.  
  368.     /*
  369.      * put it at the head of the Lru ring
  370.      */
  371.  
  372.     Insert(file);
  373.  
  374.     return (0);
  375. }
  376.  
  377. void
  378. AssertLruRoom()
  379. {
  380.     DO_DB(printf("DEBUG:    AssertLruRoom (FreeFd = %d)\n",FreeFd));
  381.  
  382.     if (FreeFd <= 0 || nfile >= MAXFILES) {
  383.         LruDelete(VfdCache[0].lruMoreRecently);
  384.     }
  385. }
  386.  
  387. int
  388. FileAccess(file)
  389.     FileNumber    file;
  390. {
  391.     int    returnValue;
  392.  
  393.     DO_DB(printf("DB: FileAccess %d (%s)\n",file,VfdCache[file].fileName));
  394.  
  395.     /*
  396.      * Is the file open?  If not, close the least recently used,
  397.      * then open it and stick it at the head of the used ring
  398.      */
  399.  
  400.     if (FileIsNotOpen(file)) {
  401.  
  402.         AssertLruRoom();
  403.  
  404.         returnValue = LruInsert(file);
  405.         if (returnValue != 0)
  406.             return returnValue;
  407.  
  408.     } else {
  409.  
  410.         /*
  411.          * We now know that the file is open and that it is not the
  412.          * last one accessed, so we need to more it to the head of
  413.          * the Lru ring.
  414.          */
  415.  
  416.         Delete(file);
  417.         Insert(file);
  418.     }
  419.  
  420.     return (0);
  421. }
  422.  
  423. FileNumber
  424. AllocateVfd()
  425. {
  426.     Index    i;
  427.     FileNumber    file;
  428.  
  429.     DO_DB(printf("DEBUG:    AllocateVfd\n"));
  430.  
  431.     if (SizeVfdCache == 0) {
  432.  
  433.         /* initialize */
  434.         VfdCache = (Vfd *)malloc(sizeof(Vfd));
  435.  
  436.         VfdCache->nextFree = 0;
  437.         VfdCache->lruMoreRecently = 0;
  438.         VfdCache->lruLessRecently = 0;
  439.         VfdCache->fd = VFD_CLOSED;
  440.         VfdCache->fdstate = 0x0;
  441.  
  442.         SizeVfdCache = 1;
  443.     }
  444.  
  445.     if (VfdCache[0].nextFree == 0) {
  446.  
  447.         /*
  448.          * The free list is empty so it is time to increase the
  449.          * size of the array
  450.          */
  451.  
  452.         VfdCache =(Vfd *)realloc(VfdCache, sizeof(Vfd)*SizeVfdCache*2);
  453.         Assert(VfdCache != NULL);
  454.  
  455.         /*
  456.          * Set up the free list for the new entries
  457.          */
  458.  
  459.         for (i = SizeVfdCache; i < 2*SizeVfdCache; i++)  {
  460.             bzero((char *) &(VfdCache[i]), sizeof(VfdCache[0]));
  461.             VfdCache[i].nextFree = i+1;
  462.             VfdCache[i].fd = VFD_CLOSED;
  463.             }
  464.  
  465.         /*
  466.          * Element 0 is the first and last element of the free
  467.          * list
  468.          */
  469.  
  470.         VfdCache[0].nextFree = SizeVfdCache;
  471.         VfdCache[2*SizeVfdCache-1].nextFree = 0;
  472.  
  473.         /*
  474.          * Record the new size
  475.          */
  476.  
  477.         SizeVfdCache *= 2;
  478.     }
  479.     file = VfdCache[0].nextFree;
  480.  
  481.     VfdCache[0].nextFree = VfdCache[file].nextFree;
  482.  
  483.         return file;
  484. }
  485.  
  486. /*
  487.  *  Called when we get a shared invalidation message on some relation.
  488.  */
  489. void
  490. FileInvalidate(file)
  491.     File file;
  492. {
  493.     Sfd *sfdP;
  494.     int i;
  495.     int n;
  496.  
  497.     /* avoid work if we can */
  498.     if (file < 0)
  499.     return;
  500.  
  501.     sfdP = &SfdCache[file];
  502.  
  503.     n = NStriping;
  504.     if (StripingMode == 1) n *= 2;
  505.     for (i=0; i<n; i++)
  506.     {
  507.     if (!FileIsNotOpen(sfdP->vfd[i]))
  508.         LruDelete(sfdP->vfd[i]);
  509.     }
  510. }
  511.  
  512. void
  513. FreeVfd(file)
  514.     FileNumber    file;
  515. {
  516.     DO_DB(printf("DB: FreeVfd: %d (%s)\n",file,VfdCache[file].fileName));
  517.  
  518.     VfdCache[file].nextFree = VfdCache[0].nextFree;
  519.     VfdCache[0].nextFree = file;
  520. }
  521.  
  522. /* VARARGS2 */
  523. FileNumber
  524. fileNameOpenFile(fileName, fileFlags, fileMode)
  525.     FileName    fileName;
  526.     int        fileFlags;
  527.     int        fileMode;
  528. {
  529.     static int osRanOut = 0;
  530.     FileNumber    file;
  531.     Vfd    *vfdP;
  532.     int     tmpfd;
  533.  
  534.     DO_DB(printf("DEBUG: FileNameOpenFile: %s %x %o\n",fileName,fileFlags,fileMode));
  535.  
  536.     file = AllocateVfd();
  537.     vfdP = &VfdCache[file];
  538.  
  539.     if (nfile >= MAXFILES || (FreeFd == 0 && osRanOut)) {
  540.         AssertLruRoom();
  541.     }
  542.  
  543. tryAgain:
  544.     tmpfd = open("/dev/null", O_CREAT|O_RDWR, 0666);
  545.     if (tmpfd < 0) {
  546.         DO_DB(printf("DB: not enough descs, retry, er= %d\n", errno));
  547.         errno = 0;
  548.         FreeFd = 0;
  549.         osRanOut = 1;
  550.         AssertLruRoom();
  551.         goto tryAgain;
  552.     } else {
  553.         close(tmpfd);
  554.     }
  555.  
  556.     vfdP->fd = open(fileName,fileFlags,fileMode);
  557.     vfdP->fdstate = 0x0;
  558.  
  559.     if (vfdP->fd < 0) {
  560.         FreeVfd(file);
  561.         return -1;
  562.     }
  563.     ++nfile;
  564.     DO_DB(printf("DB: FNOF success %d\n", vfdP->fd));
  565.  
  566.     (void)LruInsert(file);
  567.  
  568.     if (fileName==NULL) {
  569.         elog(WARN, "fileNameOpenFile: NULL fname");
  570.     }
  571.     vfdP->fileName = malloc(strlen(fileName)+1);
  572.     strcpy(vfdP->fileName,fileName);
  573.  
  574.     vfdP->fileFlags = fileFlags & ~(O_TRUNC|O_EXCL);
  575.     vfdP->fileMode = fileMode;
  576.  
  577.     return file;
  578. }
  579.  
  580. void
  581. fileClose(file)
  582.     FileNumber    file;
  583. {
  584.     int    returnValue;
  585.  
  586.     DO_DB(printf("DEBUG: FileClose: %d (%s)\n",file,VfdCache[file].fileName));
  587.  
  588.     if (!FileIsNotOpen(file)) {
  589.  
  590.         /* remove the file from the lru ring */
  591.         Delete(file);
  592.  
  593.         /* record the new free operating system file descriptor */
  594.         FreeFd++;
  595.  
  596.         /* if we did any writes, sync the file before closing */
  597.         if (VfdCache[file].fdstate & FD_DIRTY) {
  598. #ifndef linux
  599.             returnValue = fsync(VfdCache[file].fd);
  600.             Assert(returnValue != -1);
  601. #endif
  602.             VfdCache[file].fdstate &= ~FD_DIRTY;
  603.         }
  604.  
  605.         /* close the file */
  606.         returnValue = close(VfdCache[file].fd);
  607.         Assert(returnValue != -1);
  608.  
  609.         --nfile;
  610.         VfdCache[file].fd = VFD_CLOSED;
  611.     }
  612.     /*
  613.      * Add the Vfd slot to the free list
  614.      */
  615.     FreeVfd(file);
  616.     /*
  617.      * Free the filename string
  618.      */
  619.     free(VfdCache[file].fileName);
  620.  
  621.     return;
  622. }
  623.  
  624. void
  625. fileUnlink(file)
  626.     FileNumber    file;
  627. {
  628.     int returnValue;
  629.  
  630.     DO_DB(printf("DB: FileClose: %d (%s)\n",file,VfdCache[file].fileName));
  631.  
  632.     if (!FileIsNotOpen(file)) {
  633.  
  634.         /* remove the file from the lru ring */
  635.         Delete(file);
  636.  
  637.         /* record the new free operating system file descriptor */
  638.         FreeFd++;
  639.  
  640.         /* if we did any writes, sync the file before closing */
  641.         if (VfdCache[file].fdstate & FD_DIRTY) {
  642. #ifndef linux
  643.             returnValue = fsync(VfdCache[file].fd);
  644.             Assert(returnValue != -1);
  645. #endif
  646.             VfdCache[file].fdstate &= ~FD_DIRTY;
  647.         }
  648.  
  649.         /* close the file */
  650.         returnValue = close(VfdCache[file].fd);
  651.         Assert(returnValue != -1);
  652.  
  653.         --nfile;
  654.         VfdCache[file].fd = VFD_CLOSED;
  655.     }
  656.     /* add the Vfd slot to the free list */
  657.     FreeVfd(file);
  658.  
  659.     /* free the filename string */
  660.     unlink(VfdCache[file].fileName);
  661.     free(VfdCache[file].fileName);
  662.  
  663.     return;
  664. }
  665.  
  666. Amount
  667. fileRead (file, buffer, amount)
  668.     FileNumber    file;
  669.     String    buffer;
  670.     Amount    amount;
  671. {
  672.     int    returnCode;
  673.     DO_DB(printf("DEBUG: FileRead: %d (%s) %d 0x%x\n",file,VfdCache[file].fileName,amount,buffer));
  674.  
  675.     FileAccess(file);
  676.     returnCode = read(VfdCache[file].fd, buffer, amount);
  677.  
  678.     return returnCode;
  679. }
  680.  
  681.  
  682. Amount
  683. fileWrite (file, buffer, amount)
  684.     FileNumber    file;
  685.     String    buffer;
  686.     Amount    amount;
  687. {
  688.     int    returnCode;
  689.     DO_DB(printf("DB: FileWrite: %d (%s) %d 0x%lx\n",file,VfdCache[file].fileName,amount,buffer));
  690.  
  691.     FileAccess(file);
  692.     returnCode = write(VfdCache[file].fd, buffer, amount);
  693.  
  694.     /* record the write */
  695.     VfdCache[file].fdstate |= FD_DIRTY;
  696.  
  697.     return returnCode;
  698. }
  699.  
  700. long
  701. fileSeek (file, offset, whence)
  702.     FileNumber    file;
  703.     long    offset;
  704.     int    whence;
  705. {
  706.     int    returnCode;
  707.  
  708.     DO_DB(printf("DEBUG: FileSeek: %d (%s) %d %d\n",file,VfdCache[file].fileName,offset,whence));
  709.  
  710.     if (FileIsNotOpen(file)) {
  711.  
  712.         switch(whence) {
  713.           case L_SET:
  714.             VfdCache[file].seekPos = offset;
  715.             return offset;
  716.  
  717.           case L_INCR:
  718.             VfdCache[file].seekPos = VfdCache[file].seekPos +offset;
  719.             return VfdCache[file].seekPos;
  720.  
  721.           case L_XTND:
  722.             FileAccess(file);
  723.             returnCode = VfdCache[file].seekPos = 
  724.                 lseek(VfdCache[file].fd, offset, whence);
  725.             return returnCode;
  726.  
  727.           default:
  728.             elog(WARN,"should not be here in FileSeek %d", whence);
  729.             break;
  730.         }
  731.     } else {
  732.         returnCode = VfdCache[file].seekPos = 
  733.             lseek(VfdCache[file].fd, offset, whence);
  734.         return returnCode;
  735.     }
  736.  
  737.     elog(WARN,"should not be here in FileSeek #2");
  738.     return 0L;
  739. }
  740.  
  741. long
  742. fileTell (file)
  743.     FileNumber    file;
  744. {
  745.     DO_DB(printf("DEBUG: FileTell %d (%s)\n",file,VfdCache[file].fileName));
  746.     return FileSeek(file, 0, L_INCR);
  747. }
  748.  
  749. int
  750. fileSync (file)
  751.     FileNumber    file;
  752. {
  753.     int    returnCode;
  754.  
  755.     /*
  756.      *  If the file isn't open, then we don't need to sync it; we always
  757.      *  sync files when we close them.  Also, if we haven't done any
  758.      *  writes that we haven't already synced, we can ignore the request.
  759.      */
  760.  
  761.     if (VfdCache[file].fd < 0 || !(VfdCache[file].fdstate & FD_DIRTY)) {
  762.         returnCode = 0;
  763.     } else {
  764. #ifndef linux
  765.         returnCode = fsync(VfdCache[file].fd);
  766. #endif
  767.         VfdCache[file].fdstate &= ~FD_DIRTY;
  768.     }
  769.  
  770.     return returnCode;
  771. }
  772.  
  773. /*
  774.  * keep track of how many have been allocated....   give a
  775.  * warning if there are too few left
  776.  */
  777.  
  778. int allocatedFiles = 0;
  779.  
  780. /*
  781.  * Note:
  782.  *    This is expected to return on failure by AllocateFiles().
  783.  */
  784. void
  785. AllocateFile()
  786. {
  787.     int fd;
  788.  
  789.     while ((fd = open("/dev/null",O_WRONLY,0)) < 0) {
  790.         if (errno == EMFILE) {
  791.             errno = 0;
  792.             FreeFd = 0;
  793.             AssertLruRoom();
  794.         } else {
  795.             elog(WARN,"Open: %s in %s line %d\n", "/dev/null",
  796.                 __FILE__, __LINE__);
  797.         }
  798.     }
  799.     close(fd);
  800.     if (MAXFILES - ++allocatedFiles < 6)
  801.         elog(DEBUG,"warning: few useable file descriptors left (%d)",
  802.             MAXFILES - allocatedFiles);
  803.  
  804.     DO_DB(printf("DEBUG: AllocatedFile.  FreeFd = %d\n",FreeFd));
  805. }
  806.  
  807. uint16
  808. AllocateFiles(fileCount)
  809.     uint16    fileCount;
  810. {
  811.     int    fd;
  812.  
  813.     DO_DB(printf("DEBUG: Allocate Files: %d\n",fileCount));
  814.  
  815.     if (fileCount == 0) {
  816.         return (0);
  817.     }
  818.  
  819.     AllocateFile();
  820.  
  821.     fd = open("/dev/null", O_WRONLY, 0);
  822.     if (fd == -1) {
  823.         return (0);
  824.     } else {
  825.         uint16    openedFileCount =
  826.             1 + AllocateFiles(fileCount - 1);
  827.  
  828.         close(fd);
  829.  
  830.         nfile -= openedFileCount;
  831.         return (openedFileCount);
  832.     }
  833. }
  834.  
  835. /*
  836.  * What happens if FreeFile() is called without a previous AllocateFile()?
  837.  */
  838. void
  839. FreeFile()
  840. {
  841.     DO_DB(printf("DEBUG: FreeFile.  FreeFd now %d\n",FreeFd));
  842.     FreeFd++;
  843.     nfile++;            /* dangerous */
  844.     Assert(allocatedFiles > 0);
  845.     --allocatedFiles;
  846. }
  847.  
  848. /*
  849.  * What happens if FreeFiles(N) is called without a previous AllocateFile(N)?
  850.  */
  851. void
  852. FreeFiles(fileCount)
  853.     int    fileCount;
  854. {
  855.     if (fileCount >= 0) {
  856.         FreeFd += fileCount;
  857.         nfile += fileCount;    /* XXX dangerous */
  858.     }
  859.     Assert(allocatedFiles >= fileCount);
  860.     allocatedFiles -= fileCount;
  861.     DO_DB(printf("DEBUG: FreeFiles %d, FreeFd now %d\n",fileCount,FreeFd));
  862. }
  863.  
  864. static long
  865. FileSize(sfdP)
  866. Sfd *sfdP;
  867. {   int l=0, h=NStriping-1, m, nf;
  868.     long lsize, hsize, msize;
  869.     long size;
  870.     if (h == 0) {
  871.     size = fileSeek(sfdP->vfd[0], 0l, L_XTND);
  872.     return size;
  873.       }
  874.     if ((lsize = fileSeek(sfdP->vfd[l], 0l, L_XTND)) < 0) {
  875.     elog(FATAL, "lseek:%m");
  876.     }
  877.     if ((hsize = fileSeek(sfdP->vfd[h], 0l, L_XTND)) < 0) {
  878.     elog(FATAL, "lseek:%m");
  879.     }
  880.     if (lsize == hsize)
  881.        nf = 0;
  882.     else {
  883.     while (l + 1 != h) {
  884.         m = (l + h) / 2;
  885.     if ((msize = fileSeek(sfdP->vfd[m], 0l, L_XTND)) < 0) {
  886.         elog(FATAL, "lseek:%m");
  887.     }
  888.         if (msize > hsize)
  889.            l = m;
  890.         else
  891.            h = m;
  892.       }
  893.     nf = h;
  894.       }
  895.     size = hsize * NStriping + nf * BLCKSZ;
  896.     return size;
  897. }
  898.  
  899. File
  900. FileNameOpenFile(fileName, fileFlags, fileMode)
  901. FileName fileName;
  902. int fileFlags;
  903. int fileMode;
  904. {
  905.     int i;
  906.     int n;
  907.     File sfd;
  908.     Sfd *sfdP;
  909.     char *fname, *filepath();
  910.     if (SfdCache == NULL) {
  911.        SfdCache = (Sfd*)malloc(SizeSfdCache * sizeof(Sfd));
  912.        for (i=0; i<SizeSfdCache-1; i++)
  913.      SfdCache[i].nextFree = i + 1;
  914.        SfdCache[SizeSfdCache - 1].nextFree = 0;
  915.     }
  916.     sfd = SfdCache[0].nextFree;
  917.     if (sfd == 0)  {
  918.        SfdCache = (Sfd*)realloc(SfdCache, sizeof(Sfd)*SizeSfdCache*2);
  919.        Assert(SfdCache != NULL);
  920.        for (i = SizeSfdCache; i < 2*SizeSfdCache; i++) {
  921.        bzero((char *) &(SfdCache[i]), sizeof(SfdCache[0]));
  922.        SfdCache[i].nextFree = i + 1;
  923.        }
  924.        SfdCache[0].nextFree = SizeSfdCache;
  925.        SfdCache[2*SizeSfdCache-1].nextFree = 0;
  926.        SizeSfdCache *= 2;
  927.        sfd = SfdCache[0].nextFree;
  928.       }
  929.     SfdCache[0].nextFree = SfdCache[sfd].nextFree;
  930.     sfdP = &(SfdCache[sfd]);
  931.     n = NStriping;
  932.     if (StripingMode == 1) n *= 2;
  933.     for (i=0; i<n; i++) {
  934.     fname = filepath(fileName, i);
  935.     if ((sfdP->vfd[i] = fileNameOpenFile(fname, fileFlags, fileMode)) < 0)
  936.         return ((File) sfdP->vfd[i]);
  937.     }
  938.     sfdP->curStripe = 0;
  939.     sfdP->seekPos = 0;
  940.     sfdP->endPos = FileSize(sfdP);
  941.     return(sfd);
  942. }
  943.  
  944. File
  945. PathNameOpenFile(fileName, fileFlags, fileMode)
  946. FileName fileName;
  947. int fileFlags;
  948. int fileMode;
  949. {
  950.     int i;
  951.     int n;
  952.     File sfd;
  953.     Sfd *sfdP;
  954.     char *fname, *filepath();
  955.     if (SfdCache == NULL) {
  956.        SfdCache = (Sfd*)malloc(SizeSfdCache * sizeof(Sfd));
  957.        for (i=0; i<SizeSfdCache-1; i++)
  958.      SfdCache[i].nextFree = i + 1;
  959.        SfdCache[SizeSfdCache - 1].nextFree = 0;
  960.     }
  961.     sfd = SfdCache[0].nextFree;
  962.     if (sfd == 0)  {
  963.        SfdCache = (Sfd*)realloc(SfdCache, sizeof(Sfd)*SizeSfdCache*2);
  964.        Assert(SfdCache != NULL);
  965.        for (i = SizeSfdCache; i < 2*SizeSfdCache; i++) {
  966.        bzero((char *) &(SfdCache[i]), sizeof(SfdCache[0]));
  967.        SfdCache[i].nextFree = i + 1;
  968.        }
  969.        SfdCache[0].nextFree = SizeSfdCache;
  970.        SfdCache[2*SizeSfdCache-1].nextFree = 0;
  971.        SizeSfdCache *= 2;
  972.        sfd = SfdCache[0].nextFree;
  973.       }
  974.     SfdCache[0].nextFree = SfdCache[sfd].nextFree;
  975.     sfdP = &(SfdCache[sfd]);
  976.     n = NStriping;
  977.     if (StripingMode == 1) n *= 2;
  978.     for (i=0; i<n; i++) {
  979.     if ((sfdP->vfd[i] = fileNameOpenFile(fileName, fileFlags, fileMode)) < 0)
  980.         return ((File) sfdP->vfd[i]);
  981.     }
  982.     sfdP->curStripe = 0;
  983.     sfdP->seekPos = 0;
  984.     sfdP->endPos = FileSize(sfdP);
  985.     return(sfd);
  986. }
  987.  
  988. void
  989. FileClose(file)
  990. File file;
  991. {
  992.     int i;
  993.     int n = NStriping;
  994.     Sfd *sfdP;
  995.  
  996.     sfdP = &(SfdCache[file]);
  997.     if (StripingMode == 1) n *= 2;
  998.     for (i=0; i<n; i++)
  999.     fileClose(sfdP->vfd[i]);
  1000.     sfdP->nextFree = SfdCache[0].nextFree;
  1001.     SfdCache[0].nextFree = file;
  1002. }
  1003.  
  1004. extern int MyPid;
  1005.  
  1006. Amount
  1007. FileRead(file, buffer, amount)
  1008. File file;
  1009. String buffer;
  1010. Amount amount;
  1011. {
  1012.    Sfd *sfdP;
  1013.    Amount ret;
  1014. #ifdef PARALLELDEBUG
  1015.    BeginParallelDebugInfo(PDI_FILEREAD);
  1016. #endif
  1017.    sfdP = &(SfdCache[file]);
  1018.    switch (StripingMode) {
  1019.    case 0:
  1020.        ret = fileRead(sfdP->vfd[sfdP->curStripe], buffer, amount);
  1021.        sfdP->curStripe = (sfdP->curStripe + 1) % NStriping;
  1022.        break;
  1023.    case 1:
  1024.        if (MyPid % 2 == 0)
  1025.            ret = fileRead(sfdP->vfd[sfdP->curStripe], buffer, amount);
  1026.        else
  1027.            ret = fileRead(sfdP->vfd[sfdP->curStripe+NStriping], buffer, amount);
  1028.        break;
  1029.     case 5:
  1030.     /*
  1031.        printf("READ %s stripe %d row %d amount %d\n", VfdCache[sfdP->vfd[0]].fileName, sfdP->curStripe, VfdCache[sfdP->vfd[sfdP->curStripe]].seekPos/BLCKSZ, amount);
  1032.        */
  1033.        ret = fileRead(sfdP->vfd[sfdP->curStripe], buffer, amount);
  1034.        break;
  1035.       }
  1036. #ifdef PARALLELDEBUG
  1037.    EndParallelDebugInfo(PDI_FILEREAD);
  1038. #endif
  1039.    return(ret);
  1040. }
  1041.  
  1042. #define XOR(X, Y) (~(X) & (Y) | (X) & ~(Y))
  1043. static char *
  1044. blkxor(blk1, blk2, blk3, resblk)
  1045. char *blk1, *blk2, *blk3, *resblk;
  1046. {
  1047.     int i;
  1048.     char c1, c2, c3;
  1049.     char t;
  1050.     for (i=0; i<BLCKSZ; i++) {
  1051.     c1 = (blk1 == NULL)?0:blk1[i];
  1052.     c2 = (blk2 == NULL)?0:blk2[i];
  1053.     c3 = (blk3 == NULL)?0:blk3[i];
  1054.     t = XOR(c1, c2);
  1055.     resblk[i] = XOR(t, c3);
  1056.       }
  1057.     return resblk;
  1058. }
  1059.  
  1060. Amount
  1061. FileWrite(file, buffer, amount)
  1062. File file;
  1063. String buffer;
  1064. Amount amount;
  1065. {
  1066.     Sfd *sfdP;
  1067.     Amount ret;
  1068.     bool extend;
  1069.  
  1070. #ifdef PARALLELDEBUG
  1071.    BeginParallelDebugInfo(PDI_FILEWRITE);
  1072. #endif
  1073.     sfdP = &(SfdCache[file]);
  1074.     /*
  1075.     printf("WRITE %s offset %d amount %d\n", VfdCache[sfdP->vfd[0]].fileName, sfdP->seekPos, amount);
  1076.     */
  1077.     switch (StripingMode) {
  1078.     case 0:
  1079.         if (sfdP->seekPos >= sfdP->endPos)
  1080.         sfdP->endPos = sfdP->seekPos + amount;
  1081.         ret = fileWrite(sfdP->vfd[sfdP->curStripe], buffer, amount);
  1082.         sfdP->curStripe = (sfdP->curStripe + 1) % NStriping;
  1083.     break;
  1084.     case 1:
  1085.         if (sfdP->seekPos >= sfdP->endPos)
  1086.         sfdP->endPos = sfdP->seekPos + amount;
  1087.         ret = fileWrite(sfdP->vfd[sfdP->curStripe], buffer, amount);
  1088.         ret = fileWrite(sfdP->vfd[sfdP->curStripe+NStriping], buffer, amount);
  1089.     break;
  1090.     case 5:
  1091.     {
  1092.             char oldblk[BLCKSZ], oldparblk[BLCKSZ], newparblk[BLCKSZ];
  1093.         char *parblk = NULL;
  1094.         int blknum, rownum, parstripe;
  1095.         long parPos;
  1096.  
  1097.         blknum = sfdP->seekPos/BLCKSZ;
  1098.         rownum = blknum/NStriping;
  1099.         parstripe = NStriping - 1 - rownum % NStriping;
  1100.         if ((sfdP->seekPos >= sfdP->endPos) && 
  1101.         (sfdP->curStripe == 0 ||
  1102.          (parstripe == 0 && sfdP->curStripe == 1))) {
  1103.             parblk = buffer;
  1104.         if (parstripe == 0)
  1105.             sfdP->endPos = sfdP->seekPos + BLCKSZ;
  1106.         else {
  1107.             parstripe = 1;
  1108.             sfdP->endPos = sfdP->seekPos + 2 * BLCKSZ;
  1109.           }
  1110.           }
  1111.         else {
  1112.             parPos = (rownum * NStriping + parstripe) * BLCKSZ;
  1113.             if (parPos >= sfdP->endPos) {
  1114.             parPos = sfdP->endPos - BLCKSZ;
  1115.             parstripe = (parPos/BLCKSZ) % NStriping;
  1116.               }
  1117.         ret = fileSeek(sfdP->vfd[parstripe],(long)rownum*BLCKSZ,L_SET);
  1118.         /*
  1119.         printf("read old parity at stripe %d row %d\n", parstripe, VfdCache[sfdP->vfd[parstripe]].seekPos/BLCKSZ);
  1120.         */
  1121.         ret = fileRead(sfdP->vfd[parstripe], oldparblk, BLCKSZ);
  1122.         if (sfdP->seekPos >= sfdP->endPos ||
  1123.             sfdP->seekPos == parPos) {
  1124.             parblk = blkxor(oldparblk, NULL, buffer, newparblk);
  1125.           }
  1126.         else {
  1127.         /*
  1128.             printf("read old block at stripe %d row %d\n", sfdP->curStripe, VfdCache[sfdP->vfd[sfdP->curStripe]].seekPos/BLCKSZ);
  1129.             */
  1130.                 ret = fileRead(sfdP->vfd[sfdP->curStripe], oldblk, BLCKSZ);
  1131.             parblk = blkxor(oldparblk, oldblk, buffer, newparblk);
  1132.           }
  1133.             if (sfdP->seekPos >= sfdP->endPos) {
  1134.             sfdP->endPos = sfdP->seekPos + BLCKSZ;
  1135.               }
  1136.         else if (sfdP->seekPos == parPos) {
  1137.             parstripe++;
  1138.             sfdP->endPos += BLCKSZ;
  1139.           }
  1140.           }
  1141.         ret = fileSeek(sfdP->vfd[parstripe],(long)rownum*BLCKSZ,L_SET);
  1142.         /*
  1143.         printf("write parity at stripe %d row %d\n", parstripe, VfdCache[sfdP->vfd[parstripe]].seekPos/BLCKSZ);
  1144.         */
  1145.         ret = fileWrite(sfdP->vfd[parstripe], parblk, BLCKSZ);
  1146.         ret =fileSeek(sfdP->vfd[sfdP->curStripe],(long)rownum*BLCKSZ,L_SET);
  1147.         /*
  1148.         printf("write new block at stripe %d row %d\n", sfdP->curStripe, VfdCache[sfdP->vfd[sfdP->curStripe]].seekPos/BLCKSZ);
  1149.         */
  1150.             ret = fileWrite(sfdP->vfd[sfdP->curStripe], buffer, amount);
  1151.      }
  1152.        }
  1153. #ifdef PARALLELDEBUG
  1154.    EndParallelDebugInfo(PDI_FILEWRITE);
  1155. #endif
  1156.     return(ret);
  1157. }
  1158.  
  1159. long
  1160. FileSeek(file, offset, whence)
  1161. File file;
  1162. long offset;
  1163. int whence;
  1164. {
  1165.     int blknum;
  1166.     long blkoff;
  1167.     BlockNumber rownum;
  1168.     int nf, endstripe, parstripe;
  1169.     Sfd *sfdP;
  1170.     int ret;
  1171. #ifdef PARALLELDEBUG
  1172.     BeginParallelDebugInfo(PDI_FILESEEK);
  1173. #endif
  1174.  
  1175.     sfdP = &(SfdCache[file]);
  1176.     /*
  1177.     printf("SEEK %s to offset %d whence %d\n", VfdCache[sfdP->vfd[0]].fileName, offset, whence);
  1178.     */
  1179.     switch(whence) {
  1180.     case L_SET:
  1181.     switch (StripingMode) {
  1182.     case 0:
  1183.     case 1:
  1184.         sfdP->seekPos = offset;
  1185.         blknum = offset / BLCKSZ;
  1186.         blkoff = offset % BLCKSZ;
  1187.         rownum = blknum / NStriping;
  1188.         sfdP->curStripe = nf = blknum % NStriping;
  1189.         fileSeek(sfdP->vfd[nf], rownum * BLCKSZ + blkoff, whence);
  1190.         if (StripingMode == 1)
  1191.         fileSeek(sfdP->vfd[nf+NStriping],rownum*BLCKSZ+blkoff,whence);
  1192.         break;
  1193.     case 5:
  1194.         blknum = offset / BLCKSZ;
  1195.         blkoff = offset % BLCKSZ;
  1196.         rownum = blknum / (NStriping - 1);
  1197.         nf = blknum % (NStriping - 1);
  1198.         parstripe = NStriping - 1 - rownum % NStriping;
  1199.         if (nf >= parstripe) nf++;
  1200.         sfdP->curStripe = nf;
  1201.         fileSeek(sfdP->vfd[nf],rownum*BLCKSZ+blkoff,whence);
  1202.         /*
  1203.         printf("seek stripe %d to row %d\n", nf, rownum);
  1204.         */
  1205.         sfdP->seekPos = (rownum * NStriping + nf) * BLCKSZ + blkoff;
  1206.         break;
  1207.       }
  1208. #ifdef PARALLELDEBUG
  1209.     EndParallelDebugInfo(PDI_FILESEEK);
  1210. #endif
  1211.     return offset;
  1212.     case L_INCR:
  1213.     sfdP->seekPos = FileSeek(file, sfdP->seekPos + offset, L_SET);
  1214. #ifdef PARALLELDEBUG
  1215.     EndParallelDebugInfo(PDI_FILESEEK);
  1216. #endif
  1217.     return sfdP->seekPos;
  1218.     case L_XTND:
  1219.     switch (StripingMode) {
  1220.     case 0:
  1221.     case 1:
  1222.             blknum = sfdP->endPos / BLCKSZ;
  1223.             sfdP->curStripe = nf = blknum % NStriping;
  1224.         offset = fileSeek(sfdP->vfd[nf], 0L, L_XTND);
  1225.         sfdP->seekPos = sfdP->endPos = offset;
  1226.         if (StripingMode == 1) {
  1227.         fileSeek(sfdP->vfd[nf+NStriping], 0L, L_XTND);
  1228.           }
  1229.         break;
  1230.     case 5:
  1231.         sfdP->seekPos = sfdP->endPos;
  1232.         blknum = sfdP->endPos / BLCKSZ;
  1233.         rownum = blknum / NStriping;
  1234.         endstripe = blknum % NStriping;
  1235.         if (endstripe == 0)
  1236.         offset = rownum * (NStriping - 1) * BLCKSZ;
  1237.         else
  1238.             offset = (rownum * (NStriping - 1) + endstripe - 1) * BLCKSZ;
  1239.         parstripe = NStriping - 1 - rownum % NStriping;
  1240.         if (endstripe > 0 && parstripe >= endstripe) {
  1241.         sfdP->seekPos -= BLCKSZ;
  1242.         sfdP->curStripe = endstripe - 1;
  1243.         fileSeek(sfdP->vfd[endstripe - 1], rownum*BLCKSZ, L_SET);
  1244.         /*
  1245.         printf("seek stripe %d to row %d\n", endstripe-1, rownum);
  1246.         */
  1247.           }
  1248.         else {
  1249.         if (endstripe == parstripe && endstripe == 0) {
  1250.             sfdP->seekPos += BLCKSZ;
  1251.             endstripe++;
  1252.           }
  1253.         sfdP->curStripe = endstripe;
  1254.             ret = fileSeek(sfdP->vfd[endstripe], 0L, L_XTND);
  1255.         /*
  1256.         printf("seek stripe %d to row %d\n", endstripe, ret/BLCKSZ);
  1257.         */
  1258.           }
  1259.         break;
  1260.       }
  1261. #ifdef PARALLELDEBUG
  1262.     EndParallelDebugInfo(PDI_FILESEEK);
  1263. #endif
  1264.     return offset;
  1265.       }
  1266.  
  1267.     /*
  1268.      * probably never gets here, but to keep lint happy...
  1269.      */
  1270.  
  1271.     return(0);
  1272. }
  1273.  
  1274. long
  1275. FileTell(file)
  1276. File file;
  1277. {
  1278.    return SfdCache[file].seekPos;
  1279. }
  1280.  
  1281. int
  1282. FileSync(file)
  1283. File file;
  1284. {
  1285.     int i, returnCode;
  1286.     Sfd *sfdP;
  1287.     sfdP = &(SfdCache[file]);
  1288.     for (i=0; i<NStriping; i++)
  1289.        returnCode = fileSync(sfdP->vfd[i]);
  1290.     return returnCode;
  1291. }
  1292.  
  1293. char *PostgresHomes[NDISKS];
  1294. char *DBName;
  1295.  
  1296. char *
  1297. filepath(filename, stripe)
  1298. char *filename;
  1299. int stripe;
  1300. {
  1301.     char *buf;
  1302.     int len;
  1303.  
  1304.     len = strlen(PostgresHomes[stripe]) + strlen("/data/base/")
  1305.     + strlen(DBName) + strlen(filename) + 2;
  1306.     buf = (char*) palloc(len);
  1307.  
  1308.     /*
  1309.      * given absolute pathname
  1310.      */
  1311.  
  1312.     if (*filename != '/') 
  1313.     {
  1314.     sprintf(buf, "%s/data/base/%s/%s", PostgresHomes[stripe],
  1315.         DBName, filename);
  1316.     
  1317.     }
  1318.     else
  1319.     {
  1320.     strcpy(buf, filename);
  1321.     }
  1322.     return(buf);
  1323. }
  1324.  
  1325. int
  1326. FileNameUnlink(filename)
  1327. char *filename;
  1328. {
  1329.     int i, returnCode = 0;
  1330.     for (i=0; i<NStriping; i++)
  1331.        if (unlink(filepath(filename, i)) < 0)
  1332.       returnCode = -1;
  1333.     return returnCode;
  1334. }
  1335.  
  1336. BlockNumber
  1337. FileGetNumberOfBlocks(file)
  1338. File file;
  1339. {
  1340.     long len;
  1341.     BlockNumber nblks;
  1342.  
  1343.     len = FileSeek(file, 0L, L_XTND) - 1;
  1344.     return((BlockNumber)((len < 0) ? 0 : 1 + len / BLCKSZ));
  1345. }
  1346.  
  1347. void
  1348. FileUnlink(file)
  1349. File file;
  1350. {
  1351.     int i;
  1352.     int n;
  1353.     Sfd *sfdP;
  1354.  
  1355.     sfdP = &(SfdCache[file]);
  1356.  
  1357.     n = NStriping;
  1358.     if (StripingMode == 1) n *= 2;
  1359.     for (i=0; i<n; i++)
  1360.        fileUnlink(sfdP->vfd[i]);
  1361. }
  1362.  
  1363. /*--------------------------------------------------------
  1364.  *
  1365.  * FileFindName
  1366.  *
  1367.  * Return the name of the given file (used for debugging).
  1368.  *
  1369.  *--------------------------------------------------------
  1370.  */
  1371.  
  1372. char *
  1373. FileFindName(file)
  1374. File file;
  1375. {
  1376.     Sfd *sfdP;
  1377.     char *ret;
  1378.     char *fileFindName();
  1379.     char *s; int i;
  1380.  
  1381.     ret = VfdCache[file].fileName;
  1382.  
  1383.     if (ret==NULL) {
  1384.     return("<null>");
  1385.     }
  1386.     /*
  1387.      * strip the path name
  1388.      */
  1389.     i = 0;
  1390.     while (ret[i] != '\0') {
  1391.     if (ret[i] == '/') {
  1392.         s = &(ret[i+1]);
  1393.     }
  1394.     i++;
  1395.     }
  1396.  
  1397.     return(s);
  1398.  
  1399. }
  1400.  
  1401. void
  1402. closeAllVfds()
  1403. {
  1404.     int i;
  1405.     for (i=0; i<SizeVfdCache; i++) {
  1406.     if (!FileIsNotOpen(i))
  1407.         LruDelete(i);
  1408.       }
  1409. }
  1410.  
  1411. int
  1412. OurSystem(cmd)
  1413. char *cmd;
  1414. {
  1415. #ifdef sequent
  1416.     closeAllVfds();
  1417. #endif
  1418.     return system(cmd);
  1419. }
  1420.  
  1421. void
  1422. closeOneVfd()
  1423. {
  1424.     int tmpfd;
  1425.  
  1426.     tmpfd = open("/dev/null", O_CREAT | O_RDWR, 0666);
  1427.     if (tmpfd < 0) {
  1428.        FreeFd = 0;
  1429.        AssertLruRoom();
  1430.        FreeFd = 0;
  1431.      }
  1432.     else
  1433.        close(tmpfd);
  1434. }
  1435.  
  1436. int FileStat(file,stbuf)
  1437.      File file;
  1438.      struct pgstat *stbuf;
  1439. {
  1440.     int ret;
  1441.     struct stat ustatbuf;
  1442.     ret = fstat(VfdCache[SfdCache[file].vfd[0]].fd,&ustatbuf);
  1443.     if (ret >= 0) {
  1444.     stbuf->st_mode = ustatbuf.st_mode;
  1445.     stbuf->st_uid = ustatbuf.st_uid;
  1446.     stbuf->st_size = ustatbuf.st_size;
  1447.     stbuf->st_sizehigh = 0;
  1448.     stbuf->st_atime = ustatbuf.st_atime;
  1449.     stbuf->st_ctime = ustatbuf.st_ctime;
  1450.     stbuf->st_mtime = ustatbuf.st_mtime;
  1451.     }
  1452.     return ret;
  1453. }
  1454.